package org.eenie.core.base

import android.app.Dialog
import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.appcompat.app.AppCompatDialogFragment
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import org.eenie.core.R

abstract class BaseDialogFragment : AppCompatDialogFragment() {

    lateinit var mRootView: View
    lateinit var mContext: Context

    private var defaultDialogConfig = DialogConfig()
    private var waitingForDismissAllowingStateLoss = false

    override fun onCreate(savedInstanceState: Bundle?) {
        mContext = requireContext()
        initData(savedInstanceState)
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        this.dialog?.requestWindowFeature(Window.FEATURE_NO_TITLE)
        return inflater.inflate(getLayoutRes(), null)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        mRootView = view
        initUI(view)
    }

    open fun initData(savedInstanceState: Bundle?) {

    }

    abstract fun getLayoutRes(): Int

    abstract fun initUI(mRootView: View)


    override fun onStart() {
        super.onStart()
        val config = getDialogConfig()
        val dl = dialog
        val window = dl?.window
        window?.apply {
            if (!config.sheet) {
                setGravity(config.gravity)
                setLayout(config.width, config.height)
                setWindowAnimations(config.animation)
            }
            setDimAmount(config.amount)
            setBackgroundDrawable(config.background)
            runCatching {
                if (dl is BottomSheetDialog) {
                    val view = dl.findViewById<View>(R.id.design_bottom_sheet)
                    view?.background = config.background
                }
            }
        }
    }

    open fun getDialogConfig(): DialogConfig {
        return defaultDialogConfig
    }


    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return if (getDialogConfig().sheet) {
            BottomSheetDialog(requireContext(), theme)
        } else {
            super.onCreateDialog(savedInstanceState)
        }
    }

    override fun dismiss() {
        if (!tryDismissWithAnimation(false)) {
            super.dismiss()
        }
    }

    override fun dismissAllowingStateLoss() {
        if (!tryDismissWithAnimation(true)) {
            super.dismissAllowingStateLoss()
        }
    }


    private fun tryDismissWithAnimation(allowingStateLoss: Boolean): Boolean {
        val baseDialog = dialog
        if (baseDialog is BottomSheetDialog) {
            val behavior: BottomSheetBehavior<*> = baseDialog.behavior
            if (behavior.isHideable && baseDialog.dismissWithAnimation) {
                dismissWithAnimation(behavior, allowingStateLoss)
                return true
            }
        }
        return false
    }

    private fun dismissWithAnimation(behavior: BottomSheetBehavior<*>, allowingStateLoss: Boolean) {
        waitingForDismissAllowingStateLoss = allowingStateLoss
        if (behavior.state == BottomSheetBehavior.STATE_HIDDEN) {
            dismissAfterAnimation()
        } else {
            behavior.setBottomSheetCallback(BottomSheetDismissCallback())
            behavior.setState(BottomSheetBehavior.STATE_HIDDEN)
        }
    }

    private fun dismissAfterAnimation() {
        if (waitingForDismissAllowingStateLoss) {
            super.dismissAllowingStateLoss()
        } else {
            super.dismiss()
        }
    }

    private inner class BottomSheetDismissCallback : BottomSheetBehavior.BottomSheetCallback() {
        override fun onStateChanged(bottomSheet: View, newState: Int) {
            if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                dismissAfterAnimation()
            }
        }

        override fun onSlide(bottomSheet: View, slideOffset: Float) {}
    }
}